import { GameMgr } from "../GameMgr"
import { Player } from "./Player"
import { Point, Terrain } from "./Point"
import { Small } from "./Small"
import Utils from "../GameUtils"

/**
 * 大子状态
 */
export enum BigState {
    HIDE = "潜行",
    SHIELD = "护盾",
    FEAR = "怯战",
    ICE = "冰冻",
    BURDEN = "焦渴",
    METHYSIS = "中毒",
    METHYSIS_BEFORE = "微毒",    //毒爆后给周围的大子上这个状态，回合开始时把这个状态切到中毒
    BLOODTHIRSTY = "嗜血",  //攻击成功后获得1点行动
    WAVERIDER = "踏浪",     //能进入水中
    FERTILE = "旺育",        //出大消耗-1
    EXPOSE = "暴露",         //敌方能看到你
    HEROIC = "常胜"         //常胜将军，攻击成功后获得获得护盾
}

/**
 * 大子进化
 */
export enum BigEvolution {
    未转型 = "未转型",
    幽灵 = "幽灵",
    恶灵 = "恶灵",
    炮台 = "炮台",
    狙炮 = "狙炮",
    顽石 = "顽石",
    地灵 = "地灵",
    精灵 = "精灵",
    沙兵 = "沙兵",
    沙皇 = "沙皇",
    野猪 = "野猪",
    野马 = "野马",
    拳师 = "拳师",
    灵阵 = "灵阵",
    天谕 = "天谕",
    妖术 = "妖术",
    鼓舞 = "鼓舞",
    指挥 = "指挥"
}

/**
 * 大子
 */
export class Big {

    gameMgr:GameMgr
    player:Player
    point:Point
    father:Big
    mother:Small
    id:String
    arr_states:Set<BigState> = new Set()
    evolution:BigEvolution = BigEvolution.未转型
    actionTime:number = 0          //行动次数，所有棋子一回合只能行动2次，回合开始时重置

    is_death:Boolean = false      //是否已经死亡，一般用不到

    updateTimeout: NodeJS.Timeout   //通知客户端更新大子数据延迟器，防止多个地方同时调用update

    constructor(evolution: BigEvolution = BigEvolution.未转型) {
        this.evolution = evolution
    }

    init(gameMgr:GameMgr,player:Player,point:Point,monther:Small,father:Big) {
        this.gameMgr = gameMgr
        this.player = player
        this.point = point
        this.mother = monther
        this.father = father
        this.point.big = this
        this.player.arr_bigs.add(this)
        this.id = player.username + "-" + (++player.num_bornBig).toString()
        this.terrainAdapt()
    }
    
    gc() {
        this.gameMgr = null
        this.player = null
        this.point = null
        this.mother = null
        this.father = null
        this.arr_states = null
        clearTimeout(this.updateTimeout)
    }

    /**
     * 转型
     */
    evolve(big: Big) {
        this.gameMgr = big.gameMgr
        this.player = big.player
        this.point = big.point
        this.mother = big.mother
        this.father = big.father
        this.point.big = this
        this.player.arr_bigs.delete(big)
        this.player.arr_bigs.add(this)
        this.id = big.id
        this.actionTime = big.actionTime
        this.terrainAdapt()
        this.onEvolved()
    }

    /** 行动力一次 */
    actionOnce() {
        this.actionTime--
        this.update()
    }

    /**
     * 刚转型完成，有的转型体要干点什么
     */
    onEvolved() {
        this.update()
    }

    toObj() {
        let obj = {
            "id":this.id,
            "point_id":this.point.id,
            "player_username":this.player.username,
            "father_id":this.father == null ? null : this.father.id,
            "arr_states":Array.from(this.arr_states),
            "actionTime":this.actionTime
        }
        return obj
    }

    /** 延迟20ms发送,回合开始的时候一直发送不太好 */
    update() {
        clearTimeout(this.updateTimeout)
        this.updateTimeout = setTimeout(()=>{
            if (this.gameMgr != null) {
                this.gameMgr.sendBroadcast(Utils.getObj("update_big",{"big":this.toObj()},true,false),false)
            }
        },20)
    }

    /** 大子被攻击 
     *  player 凶手，被这个玩家杀死的，子系死亡时特效要给对方看到
     */
    attacked(player:Player) {
        if (this.arr_states.has(BigState.SHIELD)) {
            this.deleteState(BigState.HIDE)
            this.deleteState(BigState.SHIELD)
            return false
        } else {
            this.die(player)
        }
        return true
    }


    /** 大子死亡
     * murderer 杀人凶手，死在这个人手上的
     * effect_point_id  大子死亡的时候不一定在大子所在位置，比如自己撞对面死了，特效播放在死亡地点
     * is_show_effect   是否显示死亡动画，比如幽灵附身时，不播放
     */
    die(murderer:Player, effect_point_id:string = null, is_show_effect:Boolean = true) {
        this.gameMgr.sendBroadcast(Utils.getObj("big_die",
            {
                "point_id":this.point.id,
                "effect_point_id":effect_point_id,
                "is_show_effect":is_show_effect,
                "murderer":murderer.username
            }))
        this.point.big = null
        this.player.arr_bigs.delete(this)
        this.is_death = true
        this.player.arr_bigs.forEach(big=>{
            if (big.father == this) {
                big.die(murderer)
            }
        })
    }

    /** 儿子们死亡，转型时执行 */
    sonDie(murderer:Player) {
        this.player.arr_bigs.forEach(big=>{
            if (big.father == this) {
                big.die(murderer)
            }
        })
    }

    /** 被恶灵附身 */
    possess(big_恶灵:Big = null, big_father:Big = null) {
        let old_player = this.player
        if (big_恶灵 != null) {
            this.father = big_恶灵.father
            this.mother = big_恶灵.mother
            this.player.arr_bigs.delete(this)
            this.player = big_恶灵.player
            this.player.arr_bigs.add(this)
            let father_id = null
            if (this.father != null) {
                father_id = this.father.id
            }
            this.gameMgr.sendBroadcast(Utils.getObj("big_possess",{"point_id":this.point.id,"player_username":big_恶灵.player.username,"father_id":father_id}))
        } else {
            this.mother = big_father.mother
            this.player.arr_bigs.delete(this)
            this.player = big_father.player
            this.player.arr_bigs.add(this)
            this.gameMgr.sendBroadcast(Utils.getObj("big_possess",{"point_id":this.point.id,"player_username":big_father.player.username,"father_id":null}))
        }
        this.update()
        old_player.arr_bigs.forEach(big=>{
            if (big.father == this) {
                big.possess(null, this)
            }
        })
        this.turnStart()
    }

    /** 获得状态 */
    addState(state:BigState) {
        if(!this.arr_states.has(state)) {
            this.arr_states.add(state)
            this.update()
        }
    }

    /** 删除状态 删除隐身、焦渴 */
    deleteState(state:BigState){
        this.arr_states.delete(state)
        this.update()
    }


    /** 回合开始 */
    turnStart() {
        this.actionTime = 2
        if (this.arr_states.has(BigState.METHYSIS_BEFORE)) {
            this.addState(BigState.METHYSIS)
            this.deleteState(BigState.METHYSIS_BEFORE)
        }
        this.update()
    }

    /** 回合结束 */
    turnOver() {
        this.actionTime = 0
        this.deleteState(BigState.ICE)
        this.deleteState(BigState.FEAR)
        this.deleteState(BigState.EXPOSE)
        this.poisonousExplosion()
        this.update()
    }

    /** 地形适应 */
    terrainAdapt() {
        switch (this.point.terrain) {
            case Terrain.KONG:
                this.deleteState(BigState.HIDE)
                this.deleteState(BigState.BURDEN)
                break
            case Terrain.SHAN:
                this.die(this.player)
                break
            case Terrain.SHUI:
                if (!this.arr_states.has(BigState.WAVERIDER)) {
                    this.die(this.player)
                } 
                break
            case Terrain.LIN:
                this.addState(BigState.HIDE)
                this.deleteState(BigState.BURDEN)
                break
            case Terrain.SHA:
                this.deleteState(BigState.HIDE)
                this.addState(BigState.BURDEN)
                break
        }
    }

    /** 毒爆 */
    poisonousExplosion() {
        if(!this.arr_states.has(BigState.METHYSIS)) {
            return
        }
        this.gameMgr.sendBroadcast(Utils.getObj("play_effect",{"effect":"big_毒爆","point_id":this.point.id,"username":this.player.username}))
        if(this.arr_states.has(BigState.SHIELD)) {
            this.deleteState(BigState.SHIELD)
            this.deleteState(BigState.METHYSIS)
            return
        }
        let arr = Utils.getArrPointsAround(this.gameMgr, this.point)
        for (let p of arr) {
            let b = p.big
            if (b != null && b.player == this.player && b.evolution == BigEvolution.未转型) {
                b.addState(BigState.METHYSIS_BEFORE)
            }
        }
        this.die(this.player)
    }
}